<?php
/**
 * CRMLite Base Model Class
 *
 * @final
 * @package     Crmlite_Model
 * @version     $Id: Model.php 59 2007-09-10 03:35:38Z etng2004 $
 * @copyright   2006-2007 ETE.CN
 * @author      Yi BO  <etng2004@gmail.com>
 * @license     PHP Version 3.0 {@link http://www.php.net/license/3_0.txt}
 */
abstract class Crmlite_Model
{
	const VALIDATE_ADD     = 'add';
	const VALIDATE_UPDATE  = 'update';
	const VALIDATE_ALL     = 'update';

	const STATUS_PENDING   = 'pending';
	const STATUS_APPROVED  = 'approved';
	const STATUS_REJECTED  = 'rejected';
	const STATUS_SUSPENDED = 'suspended';
	const STATUS_ALL        = 'ALL';

	const DEFAULT_PERPAGE  = 10;

	/**
     * Database connection
     *
     * @var Zend_Db_Adapter_Abstract
     */
	protected $db = null;
	/**
	 * 数据表操作类
	 *
	 * @var Crmlite_Db_Table
	 */
	public $dbt = null;
	/**
     * 数据表名
     *
     * @var string
     */
	protected $table = '';
	/**
     * 数据表主键
     *
     * @var string
     */
	protected $primary = 'id';

	protected $error = null;

	function __construct()
	{
		$this->db = Zend_Registry::get('db');
		$db_table = 'Crmlite_Db_Table_' . substr(get_class($this), 0, -5);
		$this->dbt = new $db_table();
		$this->primary = $this->dbt->getPrimary();
	}

	public function getErrors($glue = "<br>")
	{
		return implode( $glue, (array)$this->error );
	}

	public function getError( $as_array = false)
	{
		return $this->error;
	}

	function resetError()
	{
		$this->error = array();
	}

	function pushError($name, $message)
	{
		$this->error[$name] = $message;
	}

	protected  function validate(&$record ,$mode=self::VALIDATE_ADD)
	{
		$this->error = array();
		if($mode == self::VALIDATE_ADD )
		{

		}
		elseif($mode == self::VALIDATE_UPDATE )
		{

		}

		return empty($this->error);
	}

	public function update(&$record, $where =null)
	{
		return $this->dbt->update($record, $where);
	}
	/**
	 * 由于主键可以是合并的键，成了数组，要取得唯一的键，得另外设计方法
	 *
	 * @return string	如果是合并的键，返回false
	 */
	protected function getIdentity()
	{
		if(is_array($this->primary) and sizeof($this->primary)>1)
		{
			return false;
		}
		list($itentity, ) = array_values((array)$this->primary);
		return $itentity;
	}

	public function insert(&$record)
	{
		if($this->validate($record, self::VALIDATE_ADD ))
		{
			if(!($itentity = $this->getIdentity()))
			{
				$this->dbt->insert($record);
				return true;
			}
			return $record[$itentity] = $this->dbt->insert($record);
		}
		return false;
	}

	public function replace($record)
	{
		// col names come from the array keys
		$cols = array_keys($record);
		$table =  $this->dbt->getTable();
		// build the statement
		$sql = "REPLACE INTO $table "
		. '(' . implode(', ', $cols) . ') '
		. 'VALUES (:' . implode(', :', $cols) . ')';
		$result = $this->db->query($sql, $record);
		return $result->rowCount();
	}
	public function info()
	{
		return $this->dbt->info();
	}
	public function count($where = array())
	{
		return $this->dbt->count($where);
	}
	public  function delete($where)
	{
		if(is_array($where))
		{
			$where = implode(' AND ', $where);
		}
		return $this->dbt->delete($where);
	}
	public function unDeleteById($id, $column = 'deleted_at')
	{
		return $this->restoreById($id, $column);
	}
	public function restoreById($id, $column = 'deleted_at')
	{
		$table = $this->dbt->info();
		if(!in_array($column, $table['cols']))
		{
			$this->pushError($column, 'FIEDL MISSING');
			return false;
		}
		$record = array($column => 0);
		if($itentity = $this->getIdentity())
		{
			return $this->dbt->update($record, "{$itentity}='{$id}'");
		}
		return false;
	}
	public function markDeleteById($id, $column = 'deleted_at')
	{
		return $this->trashById($id, $column);
	}
	public function trashById($id, $column = 'deleted_at')
	{
		$table = $this->dbt->info();
		if(!in_array($column, $table['cols']))
		{
			$this->pushError($column, 'FIEDL MISSING');
			return false;
		}
		$record = array($column => REQUEST_TIME);
		if($itentity = $this->getIdentity())
		{
			return $this->dbt->update($record, "{$itentity}='{$id}'");
		}
		return false;
	}
	public function deleteById($id)
	{
		if($itentity = $this->getIdentity())
		{
			return $this->dbt->delete("{$itentity}='{$id}'");
		}
		return false;
	}
	protected function isFieldExists($field_name, $field_value, $id = null )
	{
		$where = array();
		$where[] = "{$field_name}='{$field_value}'";
		is_null($id) || $where[] = "{$this->primary} = '{$id}";
		return $this->count($where);
	}

	public function statics($where = null, $field = null, $default = null)
	{
		!is_null($field) || $field = 'status';
		!is_null($default) || $default = array('pending'=>0, 'approved'=>0, 'rejected'=>0, 'suspended'=>0,);
		$statistics = $this->dbt->statics($where, $field , $default);
		array_walk($statistics,'intval');
		$statistics['ALL'] = array_sum($statistics);
		return $statistics;
	}

	public function paginate($where = null, $order= null , $page = 1 ,$limit = self::DEFAULT_PERPAGE)
	{
		$offset = ($page - 1) * $limit;
		$order || $order = implode(',' ,$this->primary) . ' DESC';
		return $this->dbt->fetchAll($where, $order, $limit, $offset)->toArray();
	}

	public function find($id)
	{
		$row = $this->dbt->find($id);
		/* @var $row Zend_Db_Table_Rowset_Abstract */
		 return $row->current()->toArray();
	}
	public function getDefault($default = array())
	{
		$db_default = $this->dbt->find(-1)->toArray();
		return array_merge($db_default, $default);
	}
	public function findAll($where = null, $order = null, $count = null,
	$offset = null)
	{
		return $this->dbt->fetchAll($where, $order, $count, $offset)->toArray();
	}

	public function fetchCol($sql, $bind = array())
	{
		return  $this->db->fetchCol($sql, $bind);
	}

	public function fetchPairs($sql, $bind = array())
	{
		return $this->db->fetchPairs($sql, $bind);
	}

	public function fetchOne($sql, $bind = array())
	{
		return $this->db->fetchOne($sql, $bind);
	}
	/**
	 * 取得Hash数组，用于Options之类的选择
	 *
	 * @param string $k_field	关键字字段，唯一
	 * @param string $v_field	值字段
	 * @return array
	 */
	public function asPairs($k_field, $v_field)
	{
		$sql = "SELECT {$k_field},{$v_field} FROM " . $this->dbt->getTable();
		return $this->fetchPairs($sql);
	}
    /**
     * 获取数组库字段中的各字段默认值
     *
     * @return string
     */
	public function getDefaults()
	{
		$meta = $this->dbt->info();
		$ret = array();
		foreach ($meta['metadata'] as $field => $meta)
		{
			$ret[$field] = $meta['DEFAULT'];
		}
		return $ret;
	}
	/**
     * 调试时使用
     *
     * 在日志中记录运行的SQL语句
     *
     * @param string $sql
     */
	function logSQL($sql)
	{
		Crmlite_App::log($sql, Zend_Log::DEBUG);
	}
}